package Util
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.filters.BlurFilter;
	import flash.filters.DisplacementMapFilter;
	import flash.geom.ColorTransform;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	[SWF(width='1024', height='512', frameRate='30')]
	public class Smoke extends Sprite
	{
		internal static var BITMAP_WIDTH:Number = 512;
		internal static var BITMAP_HEIGHT:Number = 512;
		
		internal static var WIND_SIZE:Number = 80;
		internal static var SMOKE_SIZE:Number = 10;
		
		internal var smokeBitmap:Bitmap;
		internal var displacementBitmap:Bitmap;
		internal var drawing:Boolean = false;
		internal var xPos:Number;
		internal var yPos:Number;
		internal var displacementFilter:DisplacementMapFilter;
		internal var blurFilter:BlurFilter = new BlurFilter(3, 3, 1);
		internal var windColorTransform:ColorTransform;
		internal var smokeColorTransform:ColorTransform = new ColorTransform(1, 1, 1, 1, 20, 20, 20);
		internal var dampingColorTransform:ColorTransform = new ColorTransform(.97, .96, 0, 1, 5, 9, 0, 0);
		internal var heatColorTransform:ColorTransform = new ColorTransform(1, 1, 1, 1, 0, 2, 0, 0);
		internal var bitmapRect:Rectangle = new Rectangle(0, 0, BITMAP_WIDTH, BITMAP_HEIGHT);
		internal var rect:Rectangle;
		internal var p:Point = new Point(0, 0);
		
		public function DisplacementSmoke()
		{
			smokeBitmap = new Bitmap(new BitmapData(BITMAP_WIDTH, BITMAP_HEIGHT, false, 0x000000));
			displacementBitmap = new Bitmap(new BitmapData(BITMAP_WIDTH, BITMAP_HEIGHT, false, 0x80C000));
			
			addChild(smokeBitmap);
			addChild(displacementBitmap);
			displacementBitmap.x = BITMAP_WIDTH;
			
			stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
			stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
			
			displacementFilter = new DisplacementMapFilter(displacementBitmap.bitmapData, p, 1, 2, 5, 5);
			smokeBitmap.filters = [displacementFilter];
			
			addEventListener(Event.ENTER_FRAME, enterFrameHandler);
		}
		
		internal function mouseDownHandler(event:MouseEvent):void
		{
			drawing = true;
		}
		
		internal function mouseUpHandler(event:MouseEvent):void
		{
			drawing = false;
		}
		
		internal function enterFrameHandler(event:Event):void
		{
			var i:Number;
			var j:Number;
			
			var mx:Number = stage.mouseX;
			var my:Number = stage.mouseY;
			
			var dx:Number = mx - xPos;
			var dy:Number = my - yPos;
			var d:Number = Math.sqrt(dx*dx + dy*dy);
			var step:Number = .6 - Math.min(.5, d/100);
			
			var xp:Number;
			var yp:Number;
			
			windColorTransform = new ColorTransform(1, 1, 1, 1, -dx*.5, -dy*.5);
			
			for(i=0; i<1; i+=step)
			{
				xp = xPos + dx*i;
				yp = yPos + dy*i;
				
				xp = Math.max(xp, WIND_SIZE/2);
				xp = Math.min(xp, BITMAP_WIDTH - WIND_SIZE/2);
				
				yp = Math.max(yp, WIND_SIZE/2);
				yp = Math.min(yp, BITMAP_HEIGHT - WIND_SIZE/2);
				
				if(!(xPos==0 && yPos==0))
				{              
					rect = new Rectangle(xp - WIND_SIZE/2 + Math.random()*10-5, yp - WIND_SIZE/2 + Math.random()*10-5, WIND_SIZE, WIND_SIZE);
					displacementBitmap.bitmapData.colorTransform(rect, windColorTransform);
					
					if(drawing)
					{
						displacementBitmap.bitmapData.colorTransform(rect, heatColorTransform);
						
						for(j=0; j<4; j++)
						{
							rect = new Rectangle(xp - Math.random()*SMOKE_SIZE, yp - Math.random()*SMOKE_SIZE, SMOKE_SIZE, SMOKE_SIZE);
							smokeBitmap.bitmapData.colorTransform(rect, smokeColorTransform);
						}
					}
				}
			}
			
			displacementBitmap.bitmapData.colorTransform(bitmapRect, dampingColorTransform);
			displacementBitmap.bitmapData.applyFilter(displacementBitmap.bitmapData, bitmapRect, p, blurFilter);           
			
			xPos = mx;
			yPos = my;
			
			smokeBitmap.bitmapData.draw(smokeBitmap);
		}
	}
}